/* 05-join.c

   This example demonstrates how to "wait" for thread completions by using 
   the Pthread join routine. Since some implementations of Pthreads may not 
   create threads in a joinable state, the threads in this example are 
   explicitly created in a joinable state so that they can be joined later.

   pthread.h should be first otherwise compile with -D_THREAD_SAFE 
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define NUM_THREADS	4

void *BusyWork(void *t) {
   int i;
   long tid;
   double result=0.0;

   tid = (long)t;
   printf("Thread %ld starting...\n",tid);
   for (i=0; i < 1000000; i++) result += sin(i) * tan(i);
   printf("Thread %ld done. Result = %e\n",tid, result);
   pthread_exit((void*)t);
}

int main (int argc, char *argv[]) {
   pthread_t thread[NUM_THREADS];
   pthread_attr_t attr;
   int rc;
   long t;
   void *status;   /* will have the value returned by pthread_exit */

   /* Initialize and set thread detached attribute */
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for (t=0 ; t < NUM_THREADS ; t++) {
      printf("Main: creating thread %ld\n", t);
      rc = pthread_create(&thread[t], &attr, BusyWork, (void*)t); 
      if (rc) {
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }

   /* Free attribute and wait for the other threads */
   /* Important - must give space back to OS - this language is dumb! */
   printf("Main: arrive at attr_destroy\n");
   pthread_attr_destroy(&attr);

   for (t=0 ; t < NUM_THREADS ; t++) {
      rc = pthread_join(thread[t], &status);
      if (rc) {
         printf("ERROR; return code from pthread_join() is %d\n", rc);
         exit(-1);
      }
      printf("Main: joined with thread %ld status = %ld\n",t,(long)status);
   }
 
   printf("Main: program completed. Exiting.\n");
}
